package com.shoping.web.component.other;

import com.shoping.common.health.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationFailedEvent;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.ContextStoppedEvent;

/**
 * 准确的说，这个应该不算 spring&springboot 当中的一个扩展点，ApplicationListener可以监听某个事件的event，
 * 触发时机可以穿插在业务方法执行过程中，用户可以自定义某个业务事件。但是 spring 内部也有一些内置事件，这种事件，
 * 可以穿插在启动调用中。我们也可以利用这个特性，来自己做一些内置事件的监听器来达到和前面一些触发点大致相同的事情
 * 接下来罗列下 spring 主要的内置事件：
 * <p>
 * ContextRefreshedEvent
 * ApplicationContext 被初始化或刷新时，该事件被发布。这也可以在ConfigurableApplicationContext接口中使用 refresh()方法来发生。
 * 此处的初始化是指：所有的 Bean 被成功装载，后处理 Bean 被检测并激活，所有 Singleton Bean 被预实例化，ApplicationContext容器已
 * 就绪可用。
 * <p>
 * ContextStartedEvent
 * 当使用 ConfigurableApplicationContext （ApplicationContext 子接口）接口中的 start() 方法启动 ApplicationContext时，
 * 该事件被发布。你可以调查你的数据库，或者你可以在接受到这个事件后重启任何停止的应用程序。
 * <p>
 * ContextStoppedEvent
 * 当使用 ConfigurableApplicationContext接口中的 stop()停止ApplicationContext 时，发布这个事件。你可以在接受到这个事件后
 * 做必要的清理的工作
 * <p>
 * ContextClosedEvent
 * 当使用 ConfigurableApplicationContext接口中的 close()方法关闭 ApplicationContext 时，该事件被发布。一个已关闭的上下文到达
 * 生命周期末端；它不能被刷新或重启
 * <p>
 * RequestHandledEvent
 * 这是一个 web-specific 事件，告诉所有 service HTTP 请求已经被服务。只能应用于使用 DispatcherServlet 的 Web 应用。在使用
 * Spring 作为前端的 MVC 控制器时，当 Spring 处理用户请求结束后，系统会自动触发该事件
 */
@Slf4j
@Configuration
public class MyApplicationListener implements ApplicationListener<ApplicationEvent> {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {

        log.info("【****】应用!" + event.getClass().getSimpleName());

        if (event instanceof ContextRefreshedEvent) {
            log.info("【-----】应用已准备就绪 - refreshed!");
            return;
        }

        if (event instanceof ContextClosedEvent) {
            log.info("【-----】应用已关闭 - close!");
            return;
        }

        if (event instanceof ContextStoppedEvent) {
            log.info("【-----】应用已停止 - stopped!");
            return;
        }

        if (event instanceof ApplicationStartedEvent) {
            log.info("【-----】应用启动完成 - started!");
            return;
        }

        //只有容器彻底成功后才会接受请求
        if (event instanceof ApplicationReadyEvent) {
            log.info("【-----】应用启动成功 - ready，服务就绪已开始运行!" + Constants.STD_EOF);
            return;
        }

        if (event instanceof ApplicationFailedEvent) {
            log.info("【-----】应用启动失败 - failed，进程即将退出!" + Constants.STD_EOF);

        }
    }
}
